package com.wang.gallerybackend.manager;

import cn.hutool.json.JSONUtil;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;


import javax.annotation.Resource;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

@Component
public class RedisManger {
	@Resource
	private StringRedisTemplate stringRedisTemplate;
	/**
	 *本地缓存
	 */
	private final Cache<String, String> LOCAL_CACHE = Caffeine.newBuilder()
			.initialCapacity(1024)
			.maximumSize(10_000L)
			.expireAfterWrite(Duration.ofMinutes(5))
			.build();
	/**
	 * 抽象缓存方法
	 */
	public <T> T getWithCache(String cacheKey, Supplier<T> dbQuerySupplier,long cacheTime,Class<T> clazz){
		//先查本地缓存本地缓存
		String localCacheValue = LOCAL_CACHE.getIfPresent(cacheKey);
		//本地缓存中有，则返回
		if (localCacheValue != null) {
			return JSONUtil.toBean(localCacheValue, clazz);
		}
		//2.本地缓存未命中，操作redis，缓存中没有，则查询数据库
		ValueOperations<String, String> stringStringValueOperations = stringRedisTemplate.opsForValue();
		String cacheValue = stringStringValueOperations.get(cacheKey);

		//缓存中有，则返回
		if (cacheValue != null) {
			//更新本地缓存
			LOCAL_CACHE.put(cacheKey, cacheValue);
			return JSONUtil.toBean(cacheValue, clazz);
		}
		// 3. DB 查询（由调用方决定怎么查）
		T data = dbQuerySupplier.get();
		//4.更新redis缓存和本地缓存
		//更新redis缓存
		String cacheV = JSONUtil.toJsonStr(data);
		stringStringValueOperations.set(cacheKey, cacheV, cacheTime, TimeUnit.SECONDS);
		//更新本地缓存
		LOCAL_CACHE.put(cacheKey, cacheV);
		return data;
	}
}
